import { define, Directive, DirectiveHandler } from 'cydon'
import { CTable } from './CTable'
import { API, LinkStatus, WSAPI } from '../api'
import { CommonKeys, MethodsStartsWith, error } from '../utils'
import { render } from '../utils/helper'
import { warning } from '@cydon/ui/Message'
import { getUser } from '../models/user'
import '@cydon/ui/components/CAsync'
import { getToken } from './NavBar'
import { EditPerm } from './EditPerm'

const d: DirectiveHandler = (name, value): Directive | void => {
	if (name == 'render-item') {
		return {
			deps: new Set,
			f(el: HTMLElement) {
				const key = this.key
				if (key == 'creator' || key == 'operator' || key == 'uid') {
					el.innerHTML = emt`c-async[load="getCreator(${this.item[key]})" lazy]`
					this.mount(el)
				} else if (key == 'tags')
					el.innerHTML = this[value][key].replace(/(?<=^| )-("[^"]+?"|\S+)/g, "<s>$&</s>")
				else
					el.innerText = render(key, this[value][key])
			}
		}
	}
	if (name == 'edit-key') {
		return {
			deps: new Set,
			f(this: EditableTable, el: HTMLElement) {
				const type = this.inputType
				switch (type) {
					case 'button':
						el.innerHTML = emt`a.btn.btn-sm[@click=editPerm]{编辑权限}`
						break
					case 'textarea':
						el.innerHTML = emt`textarea.input.input-bordered.input-sm[c-model.lazy="newItem[mkeys[i-1]]"
							c-if="i<=mkeys.length" placeholder="\${colName(i)}" title="\${colName(i)}"]`
						break
					case 'select':
						const options = Object.keys(LinkStatus).filter(x => +x < 4).map(
							(s: string | number) => emt`option[value=${s}]{${LinkStatus[s]}}`)
						el.innerHTML = emt`
							select.select.input-bordered.select-sm[c-model="newItem[mkeys[i-1]]"
								title="\${colName(i)}"]
									{${options.join('')}}`
						break
					default:
						el.innerHTML = emt`input[
							class="${type == 'checkbox' ? type + ' input-bordered' : 'input input-bordered input-sm'}"
							type=${type} ${this.i == 1 ? 'required form="edit"' : ''}
							c-model.lazy="newItem[mkeys[i-1]]" c-if="i<=mkeys.length"
							placeholder="\${colName(i)}" title="\${colName(i)}"]`
				}
				this.mount(el)
			}
		}
	}
}

/**
 * @element editable-table
 * 可编辑的表格
 */
@define('editable-table')
export class EditableTable<T extends {
	selected?: boolean
} = {}> extends CTable<T> {
	static observedAttributes: readonly string[] = [
		'default-item', 'object-name', ...CTable.observedAttributes]

	/** 可编辑的键 */
	mkeys!: string[]
	/** 新项目 */
	newItem: Record<string, any> = {}
	_newItem = '{}'

	get newItemJSON() {
		return this._newItem
	}
	set newItemJSON(val) {
		this.newItem = JSON.parse(this._newItem = val)
	}

	declare objectName: CommonKeys<MethodsStartsWith<WSAPI, 'get'>, MethodsStartsWith<WSAPI, 'set'>>
	i!: number
	key!: string

	/** 全选 */
	get selectAll() {
		return this.items.length > 0 && this.items.every(x => x.selected)
	}
	set selectAll(value) {
		this.items.forEach(x => x.selected = value)
	}

	connectedCallback() {
		this.mkeys = Object.keys(this.newItem)
		// 注册局部指令
		this.$directives.push(d)
		super.connectedCallback()
	}

	attributeChangedCallback(name: string, _oldVal: string, newVal: string) {
		if (name == 'default-item')
			this.newItemJSON = newVal
		super.attributeChangedCallback(name, _oldVal, newVal)
	}

	/** 获取输入框类型 */
	get inputType() {
		const key = this.mkeys[this.i - 1]
		const val = this.newItem[key]
		switch (typeof val) {
			case 'boolean':
				return 'checkbox'
			case 'number':
				return key == 'perm' ? 'button' :
					key == 'status' ? 'select' :
						'number'
		}
		return key == 'pwd' || key == 'token' ? 'password' :
			key == 'desc' ? 'textarea' : 'text'
	}

	/** 提交更改 */
	save(e: Event) {
		e.preventDefault()
		const c = this.newItem
		const args = this.mkeys.map(k => c[k])
			; (<Function>API[`set${this.objectName}`])(...args).then((n: number) => {
				this.newItemJSON = this._newItem
				if (!n)
					error('提交失败')
				this.update()
			}, error)
	}

	/** 编辑行 */
	edit(item: Record<string, any>) {
		for (const key of this.mkeys)
			this.newItem[key] = key == 'pwd' ? '' : item[key]
		this.updateValue('newItem')
	}

	/** 编辑权限 */
	editPerm() {
		if (!getToken()) {
			location.hash = '#login'
			error('请先登录')
		}
		const dialog = document.getElementById('edit-perm') as HTMLDialogElement;
		customElements.whenDefined('edit-perm').then(() => {
			(dialog.lastChild as EditPerm).data.value = +this.newItem.perm
		})
		dialog.showModal()
		dialog.addEventListener('close', () => {
			const val = dialog.returnValue
			if (val) {
				this.newItem.perm = +val
				this.updateValue('newItem')
			}
		})
	}

	/** 删除选中 */
	del() {
		const items = this.items.filter(x => x.selected)
		if (!items.length)
			warning('未选中任何项目')
		for (const item of items)
			(<Function>API[`set${this.objectName}`])((<any>item)[this.keys[0]],
				null).then(() => {
					this.update()
				}, error)
	}

	/** 删除全部 */
	delAll() {
		// TODO: 优化
		if (confirm('确定删除全部？'))
			API.deleteAll(this.objectName).then(() => {
				this.update()
			}, error)
	}

	/** 获取列名 */
	colName(i: number) {
		return this.columns[i].replace(/（.*/, '')
	}

	/** 更新内容 */
	update() {
		this.page?.updateValue('pageNum')
	}

	/** 获取创建者名称 */
	async getCreator(creator: number) {
		const user = await getUser(creator)
		return user?.name || ''
	}
}

declare global {
	interface HTMLElementTagNameMap {
		'editable-table': EditableTable
	}
}